#!/usr/local/bin/perl
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
# 
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
# 
# The Original Code is Komodo code.
# 
# The Initial Developer of the Original Code is ActiveState Software Inc.
# Portions created by ActiveState Software Inc are Copyright (C) 2000-2007
# ActiveState Software Inc. All Rights Reserved.
# 
# Contributor(s):
#   ActiveState Software Inc
# 
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
# 
# ***** END LICENSE BLOCK *****

# Conscript for building the scintilla dll (with lexer)
#   Neil Hodgson provides a makefile to build this but it duplicates
#   some stuff that is better done with Komodo's Cons built system. The
#   makefile is pretty simple anyway so it is replaced by a direct
#   Cons build system. This will have to be kept in sync.
#
#   NOTE: This *should* have been a joke in Cons, but it does not
#     know anythings about resource compilation on Windows, so have
#     to do it manually. I still don't want to just call Neil's
#     makefile because it hardcodes paths.
#

Import(
    'cons',
    'platform',
    'platformPathSep',
    'build',
    'buildType',
    'ranRegxpcomStateFileName',
    'mozComponentsDir',
    'mozLibPath',
    'mozBin',
    'mozIncludePath',
    'mozIdlIncludePath',
    'mozPluginsDir',
    'mozSrc',
    'mozObjDir',
    'mozDist',
    'mozDevelDist',
    'scintillaBuildDir',
    'idlExportDir',
    'unsiloedPythonExe',
    'build',
    'mozVersion',
    'mozVersionNumber',
    'productType',
    'buildFlavour',
    'sdkDir',
    'withTests',
);

if ($^O eq "linux") {
    Import(
        "linuxDistro",
    );
}

# Autogenerate C++ interface functions and IDL interface stubs from
# Scintilla.iface. The IDL stubs are patched into ISciMoz.template.idl to
# make ISciMoz.idl.
#
# The Scintilla.iface *must* be patched before the XPFacer is used,
# to ensure the Scintilla definitions are aware of pointer references,
# this is done in the "iface_64bit.patch" file in the patches directory.
$cons->Command(
    ["npscimoz_gen.h",
     "generated_plugin_code.h",
     "ISciMoz_lite_gen.idl.fragment",
     "ISciMoz_gen.idl.fragment",
     "ISciMoz_gen.consts.fragment",
     "ISciMoz_jswrapper_gen.fragment"],
    # files needed to do the generation
    "XPFacer.py",
    "../scintilla/include/Scintilla.iface",
    "../scintilla/scripts/Face.py",
    qq(
        $unsiloedPythonExe bin/run-in-dir.py %1:d $unsiloedPythonExe %1:f
    )
);

$cons->Command(
    "ISciMoz.idl",
    # files needed to do the generation and patching
    "ISciMoz.template.idl",
    "ISciMoz_lite_gen.idl.fragment",
    "ISciMoz_gen.idl.fragment",
    "ISciMoz_gen.consts.fragment",
    "#util/patch-template.py",
    qq(
        $unsiloedPythonExe %5 %1 %0 __ISCIMOZ_LITE_INTERFACE__ \@%2 __ISCIMOZ_INTERFACE__ \@%3 __ISCIMOZ_INTERFACE_CONSTS__ \@%4
    )
);

# build the typelibs and headers from the idl files
$cons->Install($idlExportDir, 'ISciMoz.idl');
$cons->Install($idlExportDir, 'ISciMozEvents.idl');
$cons->Install($idlExportDir, 'ISciMozController.idl');
$cons->BuildAndInstallXpt('ISciMoz.idl');
$cons->BuildAndInstallXpt('ISciMozEvents.idl');
$cons->BuildAndInstallXpt('ISciMozController.idl');
$cons->BuildHeaderFromIdl('ISciMoz.idl');
$cons->BuildHeaderFromIdl('ISciMozEvents.idl');
$cons->Preprocess('koScintillaController.p.py','koScintillaController.py');
$cons->InstallXpcomComponent('koScintillaController.py');

$cons->Command(
    'scimoz_wrapper.js',
    'scimoz_wrapper.template.js',
    'ISciMoz_jswrapper_gen.fragment',
    "#util/patch-template.py",
    qq(
        $unsiloedPythonExe %3 %1 %0 __ISCIMOZ_JS_WRAPPER_GEN__ \@%2
    ));
$cons->InstallXpcomComponent('scimoz_wrapper.js',
                             {'@activestate.com/koSciMozWrapper;1' => "{487f68c7-386a-4802-8874-b0f4912e59dc}"});

# build and install the Mozilla plugin
my $pluginName;
my $xScintillaBuildDir = DirPath($scintillaBuildDir);
my $LDFLAGS = $consLocal{'LDFLAGS'};

if ($platform eq "win") {
    $pluginName = 'npscimoz.dll';

    %consLocal = $cons->copy();

    $LDFLAGS .= " /dll kernel32.lib user32.lib gdi32.lib shell32.lib advapi32.lib xpcomglue_s.lib xul.lib nspr4.lib mozalloc.lib";
    foreach my $libDir (split(';', $mozLibPath)) {
        $LDFLAGS .= " /libpath:$libDir";
    }
    $LDFLAGS .= " /DEBUG";
    $consLocal{'CPPPATH'} = [
        "$scintillaBuildDir/include",
        "helper"];
    my $CXXFLAGS = $consLocal{'CXXFLAGS'} .
        " /W3 /D_WINDOWS /DWIN32 /DXP_WIN" .
        " /FI$mozObjDir\\mozilla-config.h" .
        " /I$mozSrc/mozilla/xpcom/ds" . # for nsObserverList.h
        " /DCONTAINER_HANDLES_EVENTS=1 /DINCLUDE_DEPRECATED_FEATURES";

    if ($buildType eq 'debug') {
        $CXXFLAGS .= " /ZI /Od /DDEBUG /D_DEBUG /MDd";
    } else {
        $CXXFLAGS .= " /Ox /DNDEBUG /D_NDEBUG /MD";
    }

    # Others parts of the build for other platforms are defining these.
    # TODO: Clean up #define's in the file. This Conscript is a mess
    #       and is causing confusion.
    $CXXFLAGS .= " /DMOZ_VERSION=$mozVersionNumber";
    $CXXFLAGS .= " /DBUILDFLAVOUR=$buildFlavour";

    foreach my $includeDir (split(';', $mozIncludePath)) {
        $CXXFLAGS .= " /I$includeDir"
    }

    $consLocal{'CXXFLAGS'} = $CXXFLAGS;
    $consLocal = new cons(%consLocal);
    my @scimozobjs = $consLocal->Objects(
        "npn_gate.cpp",
        "plugin.cxx",
        "nsSciMoz.cxx",
        "nsSciMozWin.cxx",
        "sendscintilla.cxx",
        "SciMozEvents.cxx"
        );

    $consLocal->Command("npscimoz.res",
        "npscimoz.rc",
        qq(
            rc /fo%> %<
        )
    );
    $consLocal->Command($pluginName,
        "npscimoz.def",
        "npscimoz.res",
        @scimozobjs,
        qq(
            link /nologo $LDFLAGS /out:%> /DEF:%1 %<
        )
    );
    $consLocal->Depends($pluginName,
        # scintilla must be built first (this is a little artificial because
        # this is only necessary to get the scintilla headers in the build
        # directory before this build
        "$scintillaBuildDir/bin/SciLexer.dll"
    );

    $cons->Install("$mozPluginsDir", $pluginName);
}

elsif ($platform eq "darwin") {
    $pluginName = "SciMoz";
    $pluginDir = "SciMoz.plugin";

    %consLocal = $cons->copy();
    $consLocal{'LIBS'} = "$xScintillaBuildDir/bin/scintilla.a";
    $consLocal{'LIBS'} .= " $xScintillaBuildDir/cocoa/libpcre.a";
    $consLocal{'LIBS'} .= " -Wl,-dead_strip -L$mozDevelDist/bin ";
#    $consLocal{'LIBS'} .= " -Wl,-executable_path,$mozDevelDist/bin ";
    $consLocal{'LIBS'} .= " -Wl,-executable_path,$mozBin";
    $consLocal{'LIBS'} .= " $mozDevelDist/bin/XUL $mozDevelDist/lib/libxpcomglue_s.a -lnspr4 -lmozalloc ";
    # add required frameworks
    $consLocal{'LIBS'} .= " -framework CoreFoundation -framework QuartzCore";
    # scintilla
    

    $consLocal{'CPPPATH'} = "$scintillaBuildDir/include:$scintillaBuildDir/src:$scintillaBuildDir/cocoa:$scintillaBuildDir/lexlib:$mozIncludePath";
    $consLocal{'LIBPATH'} = "$mozLibPath:$mozBin";
    $consLocal{'CXXFLAGS'} = " -Wall -Wno-non-virtual-dtor -fno-rtti -fno-common -fshort-wchar";
    # Add the global FLAGS.
    $consLocal{'CXXFLAGS'} .= " $consLocal{ENV}{'CXXFLAGS'}";
    $consLocal{'CFLAGS'} = $consLocal{ENV}{'CFLAGS'};
    $consLocal{'LDFLAGS'} = $consLocal{ENV}{'LDFLAGS'};
    $consLocal{'LDFLAGS'} .= " -bundle";
    $consLocal{'CXXFLAGS'} .= " -DSCINTILLA_HIDE_DEFINES";
    $consLocal{'CXXFLAGS'} .= " -DSCI_NAMESPACE=1 -DMACOSX=1 -DSCI_LEXER ".
                            " -DCONTAINER_HANDLES_EVENTS=1 -DINCLUDE_DEPRECATED_FEATURES".
                            " -DXP_MACOSX=1 -DNO_X11=1 -DUSE_SYSTEM_CONSOLE=1 ".
                            " -DMOZ_VERSION=$mozVersionNumber ";
    $consLocal{'CXXFLAGS'} .= " -DBUILDFLAVOUR=$buildFlavour ";
    # Define the plugin event model to use.
    $consLocal{'CXXFLAGS'} .= "-DUSE_COCOA ";
    # To have SciMoz use core animation, define the following:
    $consLocal{'CXXFLAGS'} .= "-DXP_MACOSX_USE_CORE_ANIMATION ";
    $consLocal{'CXXFLAGS'} .= "-DXP_MACOSX_USE_INVALIDATING_CORE_ANIMATION ";

    # Ensure that these are defined for use by mozilla headers
    $consLocal{'CXXFLAGS'} .= " -include $mozObjDir/mozilla-config.h " .
        " -I$mozSrc/mozilla/xpcom/ds";

    if ($buildType eq 'debug') {
        $consLocal{'CXXFLAGS'} .= " -g";
        $consLocal{'CXXFLAGS'} .= " -DNS_DEBUG -DDEBUG "; # for debugging
    } else {
        $consLocal{'CXXFLAGS'} .= " -g";
        #$consLocal{'CXXFLAGS'} .= " -Os ";
    }

    # Scintilla uses exceptions - remove any disabling of it from CXXFLAGS.
    $consLocal{'CXXFLAGS'} =~ s/-fno-exceptions //g;

    $consLocal = new cons(%consLocal);
    $consLocal->Depends("SciMoz", "$scintillaBuildDir/bin/scintilla.a");


    # Make ".mm" file wrappers - so C/C++ code gets treated as objective-C.
    $cons->Command("plugin.mm", "plugin.cxx",
                   (qq($unsiloedPythonExe util/objective_c_wrap.py %1 %0)));
    $cons->Command("nsSciMoz.mm", "nsSciMoz.cxx",
                   (qq($unsiloedPythonExe util/objective_c_wrap.py %1 %0)));
    $cons->Command("sendscintilla.mm", "sendscintilla.cxx",
                   (qq($unsiloedPythonExe util/objective_c_wrap.py %1 %0)));

    $consLocal->Program(
        $pluginName,
        "plugin.mm",
        "npn_gate.cpp",
        "nsSciMoz.mm",
        "nsSciMozCocoa.mm",
        "sendscintilla.mm",
        "SciMozEvents.cxx",
    );

    # here we build the bundle package
    # we also manually install since installRecursive likes to mess on up this.
    $cons->Command("$pluginDir/Contents/MacOS/SciMoz",
                   "SciMoz.r",
                   "Info.plist",
                   "English.lproj/InfoPlist.strings",
                   "./SciMoz",
                   (
                    qq(
$unsiloedPythonExe bin/run-in-dir.py %1:d rm -Rf SciMoz.plugin
$unsiloedPythonExe bin/run-in-dir.py %1:d mkdir -p SciMoz.plugin
$unsiloedPythonExe bin/run-in-dir.py %1:d mkdir -p SciMoz.plugin/Contents
$unsiloedPythonExe bin/run-in-dir.py %1:d mkdir -p SciMoz.plugin/Contents/MacOS
$unsiloedPythonExe bin/run-in-dir.py %1:d mkdir -p SciMoz.plugin/Contents/Resources
$unsiloedPythonExe bin/run-in-dir.py %1:d cp Info.plist SciMoz.plugin/Contents
$unsiloedPythonExe bin/run-in-dir.py %1:d chmod u+w SciMoz.plugin/Contents/Info.plist
$unsiloedPythonExe bin/run-in-dir.py %1:d cp -R English.lproj SciMoz.plugin/Contents/Resources
$unsiloedPythonExe bin/run-in-dir.py %1:d cp SciMoz SciMoz.plugin/Contents/MacOS/SciMoz
$unsiloedPythonExe bin/run-in-dir.py %1:d chmod -R a+r SciMoz.plugin
$unsiloedPythonExe bin/run-in-dir.py %1:d rm -rf $mozPluginsDir/$pluginDir
$unsiloedPythonExe bin/run-in-dir.py %1:d mkdir -p $mozPluginsDir
$unsiloedPythonExe bin/run-in-dir.py %1:d cp -R SciMoz.plugin $mozPluginsDir/$pluginDir
chmod a+rX $mozPluginsDir/$pluginDir
                   )
    ));

} 
else {
    $pluginName = "libnpscimoz.so";

    %consLocal = $cons->copy();
    $consLocal{'LIBS'} = "$xScintillaBuildDir/bin/scintilla.a";
    # PCRE is built from contrib/pcre and is required by LexUDL.
    $consLocal{'LIBS'} .= " $xScintillaBuildDir/gtk/libpcre.a";
    $consLocal{'LIBS'} .= " `pkg-config --libs gthread-2.0 gtk+-2.0 gmodule-no-export-2.0`";
    $consLocal{'LIBS'} .= " -lxpcomglue_s -lxul -lmozalloc -lplds4 -lplc4 -lnspr4 ";

    $consLocal{'CPPPATH'} = "$mozIncludePath:$scintillaBuildDir/include";
    $consLocal{'LIBPATH'} = "$mozLibPath:$pluginSdkObjDir/samples/common:../scintilla/bin";

    ## XXX PKG_CONFIG_PATH env var will point to pgkconfig dir for the platform.
    ## -DGTK is required to properly include the Scintilla headers.
    $consLocal{'CXXFLAGS'} = "`pkg-config --cflags gtk+-2.0` -DGTK -DGTK2_XEMBED";
    $consLocal{'CXXFLAGS'} .= " -DCONTAINER_HANDLES_EVENTS=1 -DINCLUDE_DEPRECATED_FEATURES ";
    $consLocal{'LDFLAGS'} = " -fPIC -Wl,-z,defs -shared ";
    # Add the global FLAGS.
    $consLocal{'CXXFLAGS'} .= $consLocal{ENV}{'CXXFLAGS'};
    $consLocal{'CFLAGS'} = $consLocal{ENV}{'CFLAGS'};
    $consLocal{'LDFLAGS'} .= $consLocal{ENV}{'LDFLAGS'};
    # Scintilla uses dynamic cast - remove any disabling of it via LDFLAGS.
    $consLocal{'LDFLAGS'} =~ s/-fno-rtti //g;

    # Ensure that these are defined for use by mozilla headers
    $consLocal{'CXXFLAGS'} .= " -include $mozObjDir/mozilla-config.h " .
        " -I$pluginSdkSrcDir/samples/include ".
        " -I$mozDevelDist/include" .
        " -I$mozSrc/mozilla/xpcom/ds" .      # required for nsIObserver includes
        " -I$mozDevelDist/include/content" .
        " -I$mozDevelDist/include/gfx" .
        " -DMOZ_VERSION=$mozVersionNumber";
        
    $consLocal{'CFLAGS'} .= " -DXP_UNIX=1";
    $consLocal{'CXXFLAGS'} .= " -DXP_UNIX=1";

    if ($platform eq "solaris") {
        # big-endian byte order indicator to license code
        $consLocal{'CXXFLAGS'} .= " -DBYTEORDER=0x4321";
        # Solaris ships with broken X11 headers that do not specify int
        # return types.  The -fpermissive flag converts the errors g++
        # would otherwise generate into warnings.
        $consLocal{'CXXFLAGS'} .= " -fpermissive"
    }

    if ($buildType eq 'debug') {
        $consLocal{'CXXFLAGS'} .= " -g";
        $consLocal{'CXXFLAGS'} .= " -DNS_DEBUG "; # for debugging
    } elsif ($buildFlavour eq 'dev') {
        $consLocal{'CXXFLAGS'} .= " -g";
    } else {
        $consLocal{'CXXFLAGS'} .= " -O2";
    }

    # On Solaris, you have to use the -mimpure-text option if you are linking
    # a shared library that links to static libs (like scintilla.a).
    if ($platform eq "solaris") {
        $consLocal{'LDFLAGS'} .= " -mimpure-text";
    }

    $consLocal = new cons(%consLocal);
    $consLocal->Depends($pluginName, "$scintillaBuildDir/bin/scintilla.a");

    #XXX have to add licensing code here as well.
    $consLocal->Program($pluginName,
        "plugin.cxx",
        "npn_gate.cpp",
        "nsSciMoz.cxx",
        "nsSciMozGtk.cxx",
        "SciMozEvents.cxx",
        "sendscintilla.cxx",
    );

    $cons->Install("$mozPluginsDir", $pluginName);
}



if ($withTests) {
    #
    # Headless SciMoz.
    #
    # Build the same as regular SciMoz, but with these slight variations:
    #   1) copy necessary scimoz files into a separate "headless" build
    #      directory - this is so Cons doesn't think were building the same
    #      file twice. Preprocess is used for this copying, there is likely
    #      a better way.
    #   2) define HEADLESS_SCIMOZ for code variation
    #   3) link with the headlessscintilla library
    #   4) create headless SciMoz xpcom component, instead of plugin object
    #

    my $headlessLibName = "headlessscintilla.a";
    my $dll_ext = "so";
    my $dll_prefix = "lib";
    my $c_ext = "cxx";
    my $o_ext = "o";
    my $include_prefix = "-I";
    my $define_prefix = "-D";
    if ($platform eq "darwin") {
        $dll_ext = "dylib";
        $c_ext = "mm";
    } elsif ($platform eq "win") {
        $dll_ext = "dll";
        $dll_prefix = "";
        $o_ext = "obj";
        $include_prefix = "/I";
        $define_prefix = "/D";
        $headlessLibName = "ScintillaHeadless.dll";
    }

    my $headlessSciMoz = "headless/${dll_prefix}koScimozHeadless.$dll_ext";
    my %consHeadless = $consLocal->copy();
    my $scintillaRealDir = substr $scintillaBuildDir, 1;  # starts with special cons "#" marker otherwise

    $consHeadless{'CXXFLAGS'} = "${include_prefix}$scintillaRealDir/headless ${include_prefix}$scintillaRealDir/src " . $consHeadless{'CXXFLAGS'};
    $consHeadless{'CXXFLAGS'} .= " ${define_prefix}HEADLESS_SCIMOZ";
    $consHeadless{'CXXFLAGS'} .= " ${include_prefix}$scintillaRealDir/../SciMoz";

    if ($platform eq "win") {
        # Windows tweaks.
        $LDFLAGS .= " /libpath:$xScintillaBuildDir/bin";
        $LDFLAGS .= " /dll scintillaheadless.lib";
        $consHeadless{'LDFLAGS'} = $LDFLAGS;
        #$consHeadless{'CXXFLAGS'} .= " /DUSE_SCIN_DIRECT";
        $consLocal->Install("$mozBin", "$scintillaBuildDir/bin/$headlessLibName");
    }

    if ($platform eq "linux") {
        # Linux tweaks.
        $consHeadless{'LIBS'} =~ s/scintilla\.a/headlessscintilla.a/;
        # Ensure to hide symbol names by default.
        $consHeadless{'CXXFLAGS'} .= " -fvisibility=hidden";
    }

    if ($platform eq "darwin") {
        # Mac tweaks
        $consHeadless{'LIBS'} .= " $xScintillaBuildDir/bin/headlessscintilla.a";
        $consHeadless{'LIBS'} .= " $xScintillaBuildDir/cocoa/libpcre.a";
        # Ensure to hide symbol names by default.
        $consHeadless{'CXXFLAGS'} .= " -fvisibility=hidden";
    }

    $consHeadless = new cons(%consHeadless);
    $consHeadless->Preprocess("plugin.cxx", "headless/plugin.cxx");
    $consHeadless->Preprocess("npn_gate.cpp", "headless/npn_gate.cpp");
    $consHeadless->Preprocess("nsSciMoz.cxx", "headless/nsSciMoz.cxx");
    $consHeadless->Preprocess("nsSciMozHeadless.cxx", "headless/nsSciMozHeadless.$c_ext");
    $consHeadless->Preprocess("SciMozEvents.cxx", "headless/SciMozEvents.cxx");
    $consHeadless->Preprocess("sendscintilla.cxx", "headless/sendscintilla.$c_ext");

    $consHeadless->Program($headlessSciMoz,
        # nsSciMoz.cxx needs to be after nsSciMozHeadless.cxx because GNU
        # ld doesn't search for symbols in previous archives;
        # see bug 95927 comment 12
        "headless/nsSciMozHeadless.$c_ext",
        "headless/nsSciMoz.cxx",
        "headless/SciMozEvents.cxx",
        "headless/sendscintilla.$c_ext",
    );
    $consHeadless->Depends($headlessSciMoz, "sendscintilla.h");
    $consHeadless->Depends($headlessSciMoz, "nsSciMoz.h");
    $consHeadless->Depends($headlessSciMoz, $pluginName); # build real SciMoz first
    $consHeadless->Depends($headlessSciMoz, "$scintillaBuildDir/bin/$headlessLibName");

    $consHeadless->InstallXpcomComponent($headlessSciMoz);
}


